﻿using Castle.DynamicProxy;
using Future.Common.Attribute;
using SqlSugar;
using System.Reflection;

namespace Future.Web.Utility
{
    /// <summary>
    /// 切入接口方法可以做一些稀奇古怪的东西
    /// 比如（log拦截（可以打印参数 方法结果等），开启数据库事务，
    /// 甚至可以开始秒表检测性能等）
    /// 最好配合attribute使用 选择性的操作
    /// 实现方式在autofac注册的时候加入EnableInterfaceInterceptors()
    /// builder.RegisterAssemblyTypes(XXXX).AsImplementedInterfaces().EnableInterfaceInterceptors().InterceptedBy(typeof(CustomAutofacAop));
    /// 实现原理类似java的动态代理，在外部调用对象的方法的时候实际上是通过代理对象来调用的方法。但是在对象的内部自己调用自己的方法的时候是调用的原始对象的方法因此，此时aop并没有切入。java spring事务失效有一种情况就是这样引起的。详细原理参加java spring容器创建对象的过程
    /// </summary>
    public class CustomAutofacAop : StandardInterceptor
    {
        private readonly ILogger<CustomAutofacAop> _logger;
        private readonly ISqlSugarClient _sqlSugarClient;

        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="sqlSugarClient"></param>
        public CustomAutofacAop(ILogger<CustomAutofacAop> logger, ISqlSugarClient sqlSugarClient)
        {
            _logger = logger;
            _sqlSugarClient = sqlSugarClient;
        }

        /// <summary>
        /// 切入接口方法
        /// </summary>
        /// <param name="invocation"></param>
        protected override void PerformProceed(IInvocation invocation)
        {
            MethodInfo method = invocation.MethodInvocationTarget ?? invocation.Method;
            RequireAttribute? requireAttribute = method.GetCustomAttribute<RequireAttribute>();

            if (requireAttribute != null)
            {
                try
                {
                    _sqlSugarClient.Ado.BeginTran();
                    base.PerformProceed(invocation);
                    _sqlSugarClient.Ado.CommitTran();
                }
                catch (Exception)
                {
                    _sqlSugarClient.Ado.RollbackTran();
                    throw;
                }
            }
            else
            {
                base.PerformProceed(invocation);
            }

            _logger.LogInformation($"方法{invocation.Method}执行完成了");
        }

        /// <summary>
        /// 方法执行前
        /// </summary>
        /// <param name="invocation"></param>
        protected override void PreProceed(IInvocation invocation)
        {
            base.PreProceed(invocation);
        }

        /// <summary>
        /// 方法执行后
        /// </summary>
        /// <param name="invocation"></param>
        protected override void PostProceed(IInvocation invocation)
        {
            base.PostProceed(invocation);
        }
    }
}
